

#include "gui_config.h"
#include "iqw_gui_layout.h"
#include "gui_core.h"

#include "log.h"

#define LLOG0       xLOG_INFO0
#define LLOG1       xLOG_INFO1

// 用于生成widget布局

#define E_LINE_MIN -80
#define E_LINE_MAX 320

// 椭圆滚盘坐标线
// 圆形滚盘时使用，获取到平滑的滚动显示坐标
#if defined(SQUARE_LCD)
static const int16_t elliptic_pts[401] = {0};
#else
static const int16_t elliptic_pts[] = 
{
120,109,105,101,98,96,94,92,90,
88,86,85,83,82,81,79,78,77,76,
74,73,72,71,70,69,68,67,66,65,
65,64,63,62,61,60,60,59,58,57,
57,56,55,55,54,53,53,52,51,51,
50,49,49,48,48,47,46,46,45,45,
44,44,43,43,42,42,41,41,40,40,
39,39,38,38,38,37,37,36,36,36,
35,35,34,34,34,33,33,32,32,32,
31,31,31,30,30,30,29,29,29,28,
28,28,27,27,27,27,26,26,26,25,
25,25,25,24,24,24,24,23,23,23,
23,22,22,22,22,21,21,21,21,21,
20,20,20,20,20,19,19,19,19,19,
19,18,18,18,18,18,18,17,17,17,
17,17,17,17,16,16,16,16,16,16,
16,16,16,15,15,15,15,15,15,15,
15,15,15,15,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,14,15,
15,15,15,15,15,15,15,15,15,15,
16,16,16,16,16,16,16,16,16,17,
17,17,17,17,17,17,18,18,18,18,
18,18,19,19,19,19,19,19,20,20,
20,20,20,21,21,21,21,21,22,22,
22,22,23,23,23,23,24,24,24,24,
25,25,25,25,26,26,26,27,27,27,
27,28,28,28,29,29,29,30,30,30,
31,31,31,32,32,32,33,33,34,34,
34,35,35,36,36,36,37,37,38,38,
38,39,39,40,40,41,41,42,42,43,
43,44,44,45,45,46,46,47,48,48,
49,49,50,51,51,52,53,53,54,55,
55,56,57,57,58,59,60,60,61,62,
63,64,65,65,66,67,68,69,70,71,
72,73,74,76,77,78,79,81,82,83,
85,86,88,90,92,94,96,98,101,105,
109,120,
};
#endif


void iqw_gui_layout_update_general_container(ui_widgets_type_t *widgets, int cnt, int16_t delta_y, uint16_t type)
{
    for(int i = 0; i < cnt; i ++)
    {
        if( type != UI_WIDGET_TYPE_BASE 
        &&  widgets[i].type != type 
        )
        {
            continue; 
        }

        widgets[i].uiContainer.delta_y = delta_y;
        
        int16_t y = widgets[i].y + widgets[i].uiContainer.delta_y + widgets[i].h / 2 ;

        if( y >= E_LINE_MIN && y <= E_LINE_MAX )
        {
            // 获取到控件的中点坐标
            widgets[i].uiContainer.delta_x = elliptic_pts[ y - E_LINE_MIN ]; 
            // 转换成实际坐标
            //widgets[i].x = x; 
        }
    }
}

void iqw_gui_layout_get_y_of_general( int16_t y, int16_t h, int16_t* x)
{
    int yy = y + h / 2;
    if( yy >= E_LINE_MIN && y <= E_LINE_MAX )
    {
        *x = elliptic_pts[ yy - E_LINE_MIN ];
    }    
}


void iqw_gui_layout_update_stopwatch_container( ui_widgets_type_t *widgets, int cnt, int16_t delta_y, uint16_t type)
{
    for(int i = 0; i < cnt; i ++)
    {
        if( type != UI_WIDGET_TYPE_BASE 
        && type != widgets[i].type
        )
        {
            continue;
        }

        ui_widgets_type_t * wg = &widgets[i];
        wg->y += delta_y;

        if(wg->y == 0 || wg->y == 180)
        {
            wg->x = 50;
        }
        else if( wg->y == 60 || wg->y == 120 )
        {
            wg->x = 30; 
        }
        else
        {
            wg->x = 0;
        }

    }
}

void iqw_gui_layout_update_exercise_container( ui_widgets_type_t * widgets, int cnt, int16_t delta_y, uint16_t type )
{
    for(int i = 0; i < cnt; i ++)
    {
        ui_widgets_type_t * wg = &widgets[i];
        if( type != UI_WIDGET_TYPE_BASE
        && type != wg->type
        )
        {
            continue;
        }

        wg->y += delta_y;

        if(wg->y == 0 || wg->y == 180)
        {
            wg->x = 50;
        }
        else if( wg->y == 60 || wg->y == 120 )
        {
            wg->x = 10; 
        }
        else
        {
            wg->x = 0;
        }

    }
}


#define FLING_COUNTS                    15 
#define FLING_FAST_COUNTS               (FLING_COUNTS - 5)
#define FLING_SLOW_COUNTS               5
#define FLING_SLOW_FIXED_PTS            15 
#define FLING_SLOW_THRESHOLD            32

enum fling_status 
{
    GUI_FLING_STATUS_DISABLE, //
    GUI_FLING_STATUS_IDLE  , //            1
    GUI_FLING_STATUS_ACC   , //          2 // 减速1
    GUI_FLING_STATUS_DAMPING, //          3 // 减速2
    GUI_FLING_STATUS_BACK_TOP, //        4 // 触底回滚
    GUI_FLING_STATUS_BACK_BOTTOM, //        5 // 触顶回滚
    GUI_FLING_STATUS_COMP       , //     6 // 直接补偿
    GUI_FLING_STATUS_SWITCH_ITEM, //     7
};


#ifndef GABS
#define GABS(x)        (((x) > 0) ? (x) : (-(x)))
#endif

// static gui_roll_mana_t gui_roll = { .instance = 1 }; 
static iqw_gui_layout_fling_t *m_local_fling = NULL;

inline void iqw_gui_layout_set_local_fling( iqw_gui_layout_fling_t* fling)
{
    m_local_fling = fling;
}
inline bool iqw_gui_layout_get_local_fling_is_enabled(void)
{
    iqw_gui_layout_fling_t* f = m_local_fling;
    bool ret = false;
    while (f != NULL)
    {
        if( f->enabled == true )
        {
            ret = true;
        }
        f = f->next;
    }
    return ret;
}

inline bool iqw_gui_layout_fling_is_disabled( iqw_gui_layout_fling_t* fling)
{
    return fling->status == GUI_FLING_STATUS_DISABLE;
}

// 1: is idle
// 0: 
inline bool iqw_gui_layout_fling_check_is_idle(iqw_gui_layout_fling_t *fling)
{
    iqw_gui_layout_fling_t* f = fling;
    
    do 
    {
        if( f->enabled ) 
        {
            return false;
        }
        f = f->next;
    }while( f != NULL );

    return true; 
}
inline void iqw_gui_layout_fling_pause(iqw_gui_layout_fling_t *fling)
{
    fling->enabled = false;
}

void iqw_gui_layout_fling_init(iqw_gui_layout_fling_t *fling, int16_t min, int16_t max, int16_t itemheight)
{
    fling->min = min;
    fling->max = max;
    fling->itemHeight = itemheight;
}

void iqw_gui_layout_fling_set(iqw_gui_layout_fling_t *fling, int16_t speed )    
{
    fling->t          = 0; 
    
    if( speed != 0 )
    {
        fling->status = GUI_FLING_STATUS_ACC;
        fling->speed = speed;
    }
    else 
    {
        fling->status = GUI_FLING_STATUS_DAMPING;
    }
    // 设置使用此fling
    
    fling->enabled = true;
    iqw_gui_view_on_fling_update();
    LLOG1("[FLING]: status = %d", fling->status );
}

inline void iqw_gui_layout_fling_on_touch_press(iqw_gui_layout_fling_t* fling)
{
    fling->enabled = false;
}

inline void iqw_gui_layout_fling_on_touch_release(iqw_gui_layout_fling_t* fling)
{
    if( fling->status != GUI_FLING_STATUS_IDLE )
    {       
        fling->enabled = true;
        iqw_gui_view_on_fling_update();
    }
}
inline void iqw_gui_layout_fling_set_stop( iqw_gui_layout_fling_t* fling)
{
    fling->enabled = true;
    fling->status = GUI_FLING_STATUS_COMP;
}

inline void iqw_gui_layout_fling_switch_item( iqw_gui_layout_fling_t* fling, bool neg)
{
    fling->status = GUI_FLING_STATUS_SWITCH_ITEM;
    if( neg )
    {
        fling->speed = -1;
    }
    else 
    {
        fling->speed = 1;
    }

    iqw_gui_view_on_fling_update();
    
    fling->enabled = true; 
}

void iqw_gui_layout_fling_set_disable( iqw_gui_layout_fling_t* fling )
{
    if( fling == NULL )
    {
        return; 
    }
    
    iqw_gui_layout_fling_t* f = fling;
    do 
    {
        f->status = GUI_FLING_STATUS_DISABLE;
        f->enabled = false;
        f = f->next;
    }while( f != NULL );
    LLOG0("[FLING]: iqw_gui_layout_fling_set_disable");
}

/*
// 更新偏移量
    instance:   实例, 为停止混乱, 需要传入注册的实例
*/
void iqw_gui_layout_fling_update( iqw_gui_layout_fling_t *fling, int16_t cur_offset, int16_t* axis_delta )
{    
    if( fling->enabled == false )
    {
        return; 
    }
    LLOG1("fling status = %d", fling->status );
    int16_t delta;
    switch( fling->status )
    {
        // 减速阶段1 
        case GUI_FLING_STATUS_ACC: 
        {
            delta = fling->speed;// -11;

            if( fling->max != fling->min )
            {
                if( (cur_offset + delta) > fling->max)
                {
                    fling->status = GUI_FLING_STATUS_BACK_TOP;
                }
                else if( (cur_offset + delta) < fling->min )
                {
                    fling->status = GUI_FLING_STATUS_BACK_BOTTOM; 
                }
            }
            fling->t ++;
            if( fling->t > FLING_FAST_COUNTS)
            {
                fling->status = GUI_FLING_STATUS_DAMPING; 
            }

            // 更新偏移量
            *axis_delta += delta; 
        }
        break; 

        // 减速阶段2 
        case GUI_FLING_STATUS_DAMPING:
        {
            int16_t distance = cur_offset % fling->itemHeight;
            if( distance == 0 && *axis_delta == 0)
            {
                fling->status = GUI_FLING_STATUS_IDLE;
                fling->enabled = false;
                LLOG0("fling damping --> disable");
                break;
            }

            if( GABS(distance) < fling->itemHeight / 2 )
            {
                delta = -cur_offset % fling->itemHeight;
            }
            else 
            {
                delta = fling->itemHeight - GABS(distance );
                if( cur_offset > 0)
                {
                    delta = -delta;
                }
            }
            
            if (GABS(delta) != 1)
            {            
                delta /= 2;
            }            

            // 更新偏移量
            *axis_delta += delta; 
        }
        break;

        // 触顶回弹
        case GUI_FLING_STATUS_BACK_TOP:
        {
            delta =  fling->max - cur_offset;
            if( delta == 0 && *axis_delta == 0 )
            {
                fling->status = GUI_FLING_STATUS_IDLE;
                fling->enabled = false;
                break;
            }
            if( GABS(delta) > 2 )
            {
                delta = (delta - 1) / 2;
            }
            *axis_delta += delta;
        }
        break; 

        // 触底回弹
        case GUI_FLING_STATUS_BACK_BOTTOM:
        {
            delta = fling->min - cur_offset;
            if( delta == 0 && *axis_delta == 0 ) 
            {
                fling->status = GUI_FLING_STATUS_IDLE;
                fling->enabled = false;
                break;
            }
            if( GABS(delta) > 2)
            {
                delta = (delta + 1) / 2;
            }
            *axis_delta += delta;
        }
        break;

        case GUI_FLING_STATUS_COMP:
        {
            int16_t distance = cur_offset % fling->itemHeight;
            if( distance == 0)
            {
                *axis_delta = 0;
                fling->status = GUI_FLING_STATUS_IDLE;
                fling->enabled = false;
                break;
            }

            if( GABS(distance) < fling->itemHeight / 2 )
            {
                delta = -cur_offset % fling->itemHeight;
            }
            else 
            {
                delta = fling->itemHeight - GABS(distance );
                if( cur_offset > 0)
                {
                    delta = -delta;
                }
            }
            // 直接补偿完成
            *axis_delta += delta; 
        }
        break;
        case GUI_FLING_STATUS_SWITCH_ITEM:
        {
            int16_t distance = cur_offset % fling->itemHeight;
            if (distance == 0 )
            {
                if( *axis_delta == 0)
                {
                    fling->status = GUI_FLING_STATUS_IDLE;
                    fling->enabled = false;
                }
                break;
            }                        
            
            delta = fling->itemHeight - GABS(distance);

            // 注意优先级
            if( fling->max != fling->min)
            {
                if( cur_offset > fling->max )
                {
                    delta = -delta;
                }
                else if( cur_offset < fling->min )
                {
                    // 占位，一定为正
                }            
                // delta 这里一定为正数
                else if (fling->speed < 0) 
                {
                    delta = -delta;
                }
            }
            else 
            {
                if( fling->speed < 0)
                {
                    delta = -delta;
                }
            }


            if( GABS(delta) > 1)         
            {
                delta /= 2;
            }


            // 更新偏移量
            *axis_delta += delta;
        }
        break;

        default:
        // do nothings 
        fling->enabled = false;         
        break;
    }    
}
